import json
import pathlib
import shutil
from fastapi import APIRouter, Header, Body, Query, Form, UploadFile, BackgroundTasks
from pydantic import BaseModel, constr, conint, ValidationError
from hutool import security
from db import FAConnection
from fastapi.encoders import jsonable_encoder
from v1_all_api.all_response import AllResponse
from v1_all_api.all_utils import file_utils, datetime_utils
from . import handler_utils
from pathlib import Path
from configs import STATIC_FILE_HOST

shouquan_api = APIRouter()


MODULE_NAME = 'Shouquan'


'''
    state状态码对应状态
    -1:待处理
    0：已拒绝
    1：已完成
'''


# 创建项目
class CreatedItem(BaseModel):
    linkman: constr(max_length=200)
    link_msg: constr(max_length=200)
    apply_msg: constr(max_length=200)
    apply_plat: constr(max_length=300)
    use_to: constr(max_length=500)
    apply_notes: constr(max_length=500)


class FlowManageItem(BaseModel):
    rid: int
    fact_state: conint(ge=0, le=1)
    fact_desc: constr(max_length=200)
    fact_public: bool


class EvaluateItem(BaseModel):
    id: int
    evaluate: int
    evaluate_plain: str
    is_anonymous: bool


# ---------------------------------------------------- 申请者处理 -------------------------------------------------------


# 申请者提交一个申请
@shouquan_api.post('/my/')
async def create_record(ruizy_token: str = Header(...), body_data: str = Form(...), file: UploadFile = Form(None)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    try:
        body_content = json.loads(body_data)
        body_item = CreatedItem(**body_content)
    except json.decoder.JSONDecodeError:
        return AllResponse.validate_error(msg='parse body_data Error,it must be JSON string')
    except ValidationError as e:
        return AllResponse.validate_error(msg='参数错误！{}'.format(e))
    # 检查是否够申请积分
    need_quota, remain_quota = handler_utils.quota_information(module_name=MODULE_NAME, user_id=person['uid'])
    if need_quota > remain_quota:
        return AllResponse.validate_error(msg='申请所需积分为: {}，当前剩余：{}。'.format(need_quota, remain_quota))
    elif need_quota <= remain_quota:
        remain_quota = remain_quota - need_quota
    # 将数据保存
    if file:
        res = await file.read()
        storage_path = file_utils.get_file_paths(module_name='ProductService/Shouquan', filename=file.filename, folder_root='Annexes', hashed=True, date_folder=None)
        with open(storage_path[0], 'wb')as f:
            f.write(res)
        mf_name = file.filename
    else:
        storage_path = ('', '')
        mf_name = ''
    sql = """
        INSERT INTO prse_shouquan (linkman,link_msg,apply_msg,apply_plat,
        use_to,apply_notes,mf_name,model_file,creator_id,state,quota) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);
    """
    apply_obj = jsonable_encoder(body_item)
    prm = (apply_obj['linkman'], apply_obj['link_msg'], apply_obj['apply_msg'], apply_obj['apply_plat'],
           apply_obj['use_to'], apply_obj['apply_notes'], mf_name, storage_path[1], person['uid'], 0, remain_quota)
    with FAConnection() as cursor:
        c = cursor.execute(sql, prm)
    return AllResponse.create_successfully(msg='提交成功，请前往记录查看.') if c else AllResponse.server_error()


# 返回自己的申请记录
@shouquan_api.get('/my/')
def query_my_record(ruizy_token: str = Header(...),
                    page: int = Query(...), page_size: int = Query(...)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    # 查询自己的申请记录
    sql = """
      SELECT * FROM prse_shouquan WHERE creator_id=%s ORDER BY create_time DESC;
    """

    db_conn = FAConnection()
    ret = db_conn.query_paginator(sql, [person['uid']], page=page, page_size=page_size)
    states = {
        -1: '拒绝',
        0: '等待中',
        1: '进行中',
        2: '完成'
    }
    for row in ret['data']:
        row['create_time'] = datetime_utils.to_string(row['create_time'], is_time=True)
        row['finish_time'] = datetime_utils.to_string(row['finish_time'], is_time=True)
        row['state_text'] = states.get(row['state'], '未知')
        row['annex_public'] = True if row['annex_public'] else False
        if row['annex_file'] and row['annex_public']:
            row['has_annex'] = True
            row['annex_url'] = STATIC_FILE_HOST + row['annex_file']
        else:
            row['annex_url'] = ''
            row['annex_name'] = '无'
            row['has_annex'] = False
        if row['model_file']:
            row['model_file_url'] = STATIC_FILE_HOST + row['model_file']
        print(row)

    return AllResponse.operate_successfully(data=ret)


# ---------------------------------------------------- 工作员处理 -------------------------------------------------------


# 返回所有人员的申请记录
@shouquan_api.get('/worker/')
def query_apply_record_tome(ruizy_token: str = Header(...), page: int = Query(1), page_size: int = Query(30)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    # 查询自己的申请记录
    sql = """
          SELECT * FROM prse_shouquan where id>=%s ORDER BY create_time DESC;
        """
    db_conn = FAConnection()
    ret = db_conn.query_paginator(sql, [0], page=page, page_size=page_size)
    for i in ret['data']:
        if i['model_file']:
            i['model_file'] = i['model_file'].split("/")[-2] + '/' + i['model_file'].split("/")[-1]
    return AllResponse.operate_successfully(data=ret)


# ---------------------------------------------------- 管理员处理 -------------------------------------------------------


# 管理员根据处理状态查询
@shouquan_api.get('/manage/')
def query_manage_record(ruizy_token: str = Header(...), page: int = Query(1), page_size: int = Query(30), state: str = Query(...),):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    # 查询自己的申请记录
    sql = """
              SELECT * FROM prse_shouquan where id>=%s and state=%s ORDER BY create_time DESC;
            """
    db_conn = FAConnection()
    ret = db_conn.query_paginator(sql, [0, state], page=page, page_size=page_size)
    for i in ret['data']:
        if i['model_file']:
            i['model_file'] = i['model_file'].split("/")[-2] + '/' + i['model_file'].split("/")[-1]
    return AllResponse.operate_successfully(data=ret)


def file_convert(url: pathlib.Path):
    preview_folder = url.parent.joinpath(url.name + 'img')
    if not preview_folder.exists():
        preview_folder.mkdir(parents=True)
    else:
        shutil.rmtree(preview_folder, ignore_errors=True)
    # 文件转化为图片
    images = handler_utils.covert_file2image(url)
    if len(images) < 1:
        return 0
    else:
        return 1


# 管理员操作流程
@shouquan_api.post('/manage/')
async def manage_record_flow(background_tasks: BackgroundTasks, ruizy_token: str = Header(...), fact_data: str = Form(...), file: UploadFile = Form(None)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    try:
        body_content = json.loads(fact_data)
        body_item = FlowManageItem(**body_content)
    except json.decoder.JSONDecodeError:
        return AllResponse.validate_error(msg='parse body_data Error,it must be JSON string')
    except ValidationError as e:
        return AllResponse.validate_error(msg='参数错误！{}'.format(e))
    # 查询记录
    with FAConnection() as cursor:
        cursor.execute('SELECT * FROM prse_shouquan WHERE id=%s LIMIT 1;', [body_item.rid])
        _obj = cursor.fetchone()
        if not _obj:
            return AllResponse.validate_error(msg='操作的记录不存在')
        if _obj['state'] == 0:
            return AllResponse.validate_error(msg=f'状态为已拒绝,无需再操作。')
        elif _obj['state'] == 1:
            return AllResponse.validate_error(msg=f'状态为已完成,无需再操作。')
        # 将数据保存
        if file:
            res = await file.read()
            storage_path = file_utils.get_file_paths(module_name='ProductService/Shouquan', filename=file.filename,
                                                     folder_root='Annexes', hashed=True, date_folder=None)
            with open(storage_path[0], 'wb') as f:
                f.write(res)
            filename = file.filename
            background_tasks.add_task(file_convert, Path(storage_path[0]))
        else:
            storage_path = ('', '')
            filename = ''
        # 更新状态
        if body_item.fact_public:
            body_item.fact_public = 1
        else:
            body_item.fact_public = 0
        if body_item.fact_state == 1:
            c = cursor.execute('UPDATE prse_shouquan SET state=%s,state_plain=%s,annex_public=%s,annex_file=%s,annex_name=%s,annex_time=NOW() WHERE id=%s LIMIT 1;',
                               [1, body_item.fact_desc, body_item.fact_public, storage_path[1], filename, body_item.rid])
        else:
            c = cursor.execute('UPDATE prse_shouquan SET state=%s,state_plain=%s,annex_public=%s,annex_file=%s,annex_name=%s,annex_time=NOW() WHERE id=%s LIMIT 1;',
                               [0, body_item.fact_desc, body_item.fact_public, storage_path[1], filename, body_item.rid])
        return AllResponse.create_successfully(msg='审核成功，请前往记录查看.') if c else AllResponse.server_error()


# -------------------------------------------------- 通用处理 -----------------------------------------------------------

# 预览材料文件
@shouquan_api.get('/my/dataPreView/')
def preview_record_file(ruizy_token: str = Header(...), rid: int = Query(...), note: int = Query(None), status: int = Query(None)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    # 上传资料时已经
    if status:
        return AllResponse.validate_error('文件转换失败!')
    # 查询数据资料
    with FAConnection() as cursor:
        if note:
            cursor.execute('SELECT id,linkman,model_file FROM prse_shouquan WHERE id=%s LIMIT 1;', (rid,))
        else:
            cursor.execute('SELECT id,linkman,annex_file FROM prse_shouquan WHERE id=%s LIMIT 1;', (rid, ))
        obj = cursor.fetchone()
        if not obj:
            return AllResponse.server_no_content(msg='数据不存在')
    if note:
        if not obj['model_file']:
            return AllResponse.validate_error('还没有资料文件')
    else:
        if not obj['annex_file']:
            return AllResponse.validate_error('还没有资料文件')
    # 资料文件
    if note:
        annex_file = pathlib.Path(r'D:/FILE_STORAGE/').joinpath(obj['model_file'])
    else:
        annex_file = pathlib.Path(r'D:/FILE_STORAGE/').joinpath(obj['annex_file'])
    if not annex_file.exists():
        return AllResponse.server_no_content(msg='数据资料不存在')
    # 读取预览图片文件
    preview_folder = annex_file.parent.joinpath(annex_file.name + 'img')
    if preview_folder.exists() and not preview_folder.is_file():
        # 存在着预览的图片文件，读取文件信息
        if annex_file.name.endswith('.ppt') or annex_file.name.endswith('.pptx'):
            images = file_utils.get_file_list(preview_folder, glob='*.jpg', replaces=['幻灯片', '.JPG'])
        else:
            images = file_utils.get_file_list(preview_folder, glob='*.png')
    else:
        # 不存在，就得转化
        images = handler_utils.covert_file2image(annex_file)
        if len(images) < 1:
            return AllResponse.validate_error(msg='不支持预览的资料')
    images = [str(i).replace('\\', '/').replace('D:/FILE_STORAGE/', STATIC_FILE_HOST) for i in images]
    return AllResponse.operate_successfully(data={
        'id': rid,
        'topic': obj['linkman'],
        'images': images
    })


# 对一个申请结果评价
@shouquan_api.post('/myEvaluate/')
def evaluate_my_record(ruizy_token: str = Header(...), evaluate: EvaluateItem = Body(...)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    # 检查是否评价过了
    sql = """
      UPDATE prse_shouquan SET evaluate=%s,evaluate_plain=%s,is_anonymous=%s WHERE id=%s AND creator_id=%s LIMIT 1;
    """
    prm = (evaluate.evaluate, evaluate.evaluate_plain, evaluate.is_anonymous, evaluate.id, person['uid'])
    with FAConnection() as cursor:
        cursor.execute('SELECT id,evaluate,annex_name,annex_file,annex_public FROM prse_shouquan WHERE id=%s AND creator_id=%s LIMIT 1;',
                       (evaluate.id, person['uid']))
        obj = cursor.fetchone()
        if not obj:
            return AllResponse.no_do_anything(msg='未检测到该条数据，评价失败.')
        if obj['evaluate'] and obj['evaluate'] > 0:
            return AllResponse.validate_error(msg='您已经评价过，无需重复评价.')
        cursor.execute(sql, prm)
    # 返回附件地址
    annex_url = ''
    if obj['annex_file'] and obj['annex_public']:
        annex_url = obj['annex_file']
    return AllResponse.operate_successfully(msg='评价成功', data={
        'evaluate': evaluate.evaluate, 'id': evaluate.id, 'annex_url': annex_url,
        'has_annex': True if annex_url else False
    })
